import random
import re
from io import BytesIO

import execjs
from PIL import Image

from geetest_crack.config import common_login_headers
from geetest_crack.utils.fetch import fetch


def get_s():
    """生成随机16位字符串"""

    def _():
        return str(hex((int((1 + random.random()) * 65536) | 0)))[3:]

    return _() + _() + _() + _()


full_page_t1_js_path = './my_js/fullpage_t1.js'
full_page_w1_js_path = './my_js/fullpage_w1.js'
full_page_w2_js_path = './my_js/fullpage_w2.js'
u_js_path = './my_js/u_params.js'
slide_a_js_path = './my_js/slide_a.js'
slide_u_js_path = './my_js/encrypt.js'
my_gct_js_path = './my_js/my_gct.js'


def get_js_object(js_file_path, code_type='gbk'):
    """获取js可执行对象"""
    with open(js_file_path, encoding=code_type) as f:
        js_file = f.read()
        return execjs.compile(js_file)


full_page_t1_js = get_js_object(full_page_t1_js_path, code_type='utf8')
full_page_w1_js = get_js_object(full_page_w1_js_path, code_type='utf8')
full_page_w2_js = get_js_object(full_page_w2_js_path, code_type='utf8')
u_js = get_js_object(u_js_path)
slide_u_js = get_js_object(slide_u_js_path)
slide_a_js = get_js_object(slide_a_js_path)
my_gct_js = get_js_object(my_gct_js_path)


def get_full_page_t1(s):
    """获取fullpage的t1参数"""
    return full_page_t1_js.call('get_t', s)


def get_full_page_w1(gt, challenge, s):
    """获取fullpage的w1参数"""
    t = get_full_page_t1(s)
    return full_page_w1_js.call('get_w', gt, challenge, s, t)


def get_full_page_w2(gt, challenge, s, get_data):
    """获取fullpage的w2参数"""
    return full_page_w2_js.call('get_w', gt, challenge, s, get_data)


def get_slide_w(gt, challenge, s, track, cc, ss, ct_kv):
    """获取slide的w参数"""
    u = {
        'lang': 'zh-cn',
        'userresponse': u_js.call('getUserResponse', track[-1][0] - 1, challenge),
        'passtime': track[-1][-1],
        'imgload': random.randint(110, 300),
        'aa': u_js.call("my_aa", track, cc, ss),
        'ep': u_js.call("get_ep"),
        'rp': u_js.call("lmWn", gt + challenge[0:32] + str(track[-1][-1])),
        # very important:second validate,dynamic param
        ct_kv[0]: ct_kv[1]
    }
    u = slide_u_js.call('_encrypt', u, s)
    # same with get.php(1)'w back_part
    a = slide_a_js.call('encrypt_a', s)
    return u + a


def get_track(x):
    return u_js.call('get_track_arr', x)


def get_captcha_image(session, image_url) -> Image:
    """获取验证码图片Image对象"""
    resp = fetch(session, url=image_url, headers=common_login_headers)
    return None if resp is None else Image.open(BytesIO(resp.content))


def get_w2_dy_kv(gct_js):
    # # for slide7.8.4
    # return ['gdmb', '1349311058']

    if gct_js is None or gct_js.startswith('(function()') is False:
        print('计算gct_value文本有错:', gct_js)
        return None
    try:
        mark_fun_name = re.search('var\\s(\\w)=function\(\)', gct_js).group(1)
        mark_fun_state = 'var ' + mark_fun_name + '=function()'
        # 计算gct动态key
        gct_index_js = gct_js[gct_js.find('\'use strict\';') + len('\'use strict\';'): gct_js.find(mark_fun_state)]
        gct_index = re.search('(\\d+)', gct_index_js).group(0)
        dict_js0 = gct_js[gct_js.find('{case 2:return{') + len('{case 2:return{'):gct_js.find('\')};break;}}}()') + 2]
        dict_js = dict_js0[dict_js0.find(':function') + 1:]
        dict_func_name = dict_js0[:dict_js0.find(':function')]
        jjs = execjs.compile('var ' + dict_func_name + '=' + dict_js)
        ct_key = jjs.call(dict_func_name, int(gct_index))
        # 计算gct动态value
        c2 = gct_js[gct_js.find(mark_fun_state) + len(mark_fun_state): gct_js.rfind('return function(')]
        FkFz = c2[c2.find('function'): c2.find('}}function') + 2]
        GcKN = c2[c2.rfind('}}function') + 2:]
        # # old version
        # ct_value = gct_FkFz(GcKN + str(gct_FkFz(FkFz)))
        # new version: slide7.8.4
        ct_value = my_gct_js.call('cal_gct_value', ct_key, FkFz, GcKN)
        print('计算gct得: %s --- %s ' % (ct_key, ct_value))
        return [ct_key, str(ct_value)]
    except ValueError as err:
        print('计算gct_value出错:', err)
        return None


def gct_FkFz(t):
    e = 5381
    for o in range(len(t)):
        e = int_overflow(int_overflow(e << 5) + e + ord(t[o]))
    e &= ~(1 << 31)
    return int_overflow(e)


def int_overflow(val):
    maxint = 2147483647
    if not -maxint - 1 <= val <= maxint:
        val = (val + (maxint + 1)) % (2 * (maxint + 1)) - maxint - 1
    return val


def captcha_token(addHashF, mFunc, t):
    """
    :param addHashF: addHash["toString"]()
    :param mFunc: vFIK["toString"]()
    :param t: "bbOy"，目前看是固定值，应该会随版本发生变化
    :return:
    """
    return gct_FkFz(addHashF + str(gct_FkFz(mFunc)) + str(gct_FkFz(t)))


def get_captcha_token_by_addHash_Func(addHashF):
    mm = addHashF[addHashF.rfind('function'): addHashF.find('new Date()')]
    # 此处"bbOy"作为固定值写死，但很可能非固定值，排查问题时，请注意！
    return captcha_token(addHashF, mm, "bbOy")


if __name__ == '__main__':
    # captcha_token
    # aaa = "function addHash(e,t){var evqX=AVech.DHD,dywboJ=['heimP'].concat(evqX),fqQb=dywboJ[1];dywboJ.shift();var gKbU=dywboJ[0];function vvXn(e){var AEL=AVech.EIy()[4][10];for(;AEL!==AVech.EIy()[0][9];){switch(AEL){case AVech.EIy()[0][10]:var t=5381;var r=e[evqX(108)],n=0;while(r--){t=(t<<5)+t+e[fqQb(136)](n++);}t&=~(1<<31);return t;break;}}}new Date()[fqQb(350)]()-t[fqQb(350)]()>100&&(e=fqQb(1340));uqUq=evqX(524)+r[evqX(1317)]+fqQb(1314)+vvXn(addHash[evqX(266)]()+vvXn(vvXn[evqX(266)]())+vvXn(e[fqQb(266)]()))+fqQb(505)+fqQb(540);}";
    # aaa = "function addHash(e,t){var NHuL=AHboY.DdE,MGNXIX=['QOpbK'].concat(NHuL),OUQX=MGNXIX[1];MGNXIX.shift();var PGFJ=MGNXIX[0];function xRKd(e){var CxX=AHboY.Eav()[0][16];for(;CxX!==AHboY.Eav()[12][11];){switch(CxX){case AHboY.Eav()[10][16]:var t=5381;CxX=AHboY.Eav()[6][15];break;case AHboY.Eav()[4][15]:var r=e[OUQX(84)],n=0;CxX=AHboY.Eav()[6][14];break;case AHboY.Eav()[6][14]:while(r--){t=(t<<5)+t+e[NHuL(95)](n++);}CxX=AHboY.Eav()[6][13];break;case AHboY.Eav()[8][13]:t&=~(1<<31);CxX=AHboY.Eav()[0][12];break;case AHboY.Eav()[4][12]:return t;break;}}}new Date()[NHuL(311)]()-t[OUQX(311)]()>100&&(e=OUQX(1318));wuTQ=OUQX(589)+r[NHuL(1342)]+NHuL(1366)+xRKd(addHash[NHuL(235)]()+xRKd(xRKd[NHuL(235)]())+xRKd(e[OUQX(235)]()))+NHuL(539)+NHuL(526);}";
    # aaa = "function addHash(e,t){var IkZE=ALyZL.DyD,HSINyo=['LlJMS'].concat(IkZE),JAsB=HSINyo[1];HSINyo.shift();var KJbT=HSINyo[0];function wmOA(e){var EOD=ALyZL.EPb()[0][18];for(;EOD!==ALyZL.EPb()[8][17];){switch(EOD){case ALyZL.EPb()[12][18]:var t=5381;var r=e[IkZE(21)],n=0;while(r--){t=(t<<5)+t+e[JAsB(91)](n++);}t&=~(1<<31);return t;break;}}}new Date()[JAsB(354)]()-t[IkZE(354)]()>100&&(e=IkZE(1361));vZhW=JAsB(510)+r[IkZE(1313)]+JAsB(1348)+wmOA(addHash[IkZE(255)]()+wmOA(wmOA[IkZE(255)]())+wmOA(e[JAsB(255)]()))+IkZE(570)+JAsB(513);}"
    aaa = "function addHash(e,t){var esZZ=AXzPo.DVn,deyMbo=['htpBh'].concat(esZZ),fATm=deyMbo[1];deyMbo.shift();var gJaj=deyMbo[0];function vrju(e){var DRf=AXzPo.Ecs()[10][14];for(;DRf!==AXzPo.Ecs()[4][13];){switch(DRf){case AXzPo.Ecs()[12][14]:var t=5381;var r=e[fATm(67)],n=0;while(r--){t=(t<<5)+t+e[esZZ(86)](n++);}t&=~(1<<31);return t;break;}}}new Date()[esZZ(325)]()-t[esZZ(325)]()>100&&(e=esZZ(1337));uHyn=esZZ(532)+r[esZZ(1378)]+esZZ(1367)+vrju(addHash[fATm(250)]()+vrju(vrju[esZZ(250)]())+vrju(e[fATm(250)]()))+esZZ(515)+fATm(554);}"
    print(get_captcha_token_by_addHash_Func(aaa))

    # get_w2_ct
    # fss = r'function GcKN(t){var cKV=AZsTZ.ECM()[0][19];for(;cKV!==AZsTZ.ECM()[15][17];){switch(cKV){case AZsTZ.ECM()[6][19]:if(t[SZmB(33)]&&t[TCOx(20)]){t[e]=FkFz(GcKN[SZmB(62)]()+FkFz(FkFz[TCOx(62)]()))+TCOx(60);}cKV=AZsTZ.ECM()[12][18];break;case AZsTZ.ECM()[3][18]:return FkFz(FkFz[TCOx(62)]());break;}}}'
    # print(gct_FkFz(fss))

    # calculate ajax_w[2].ct
    # with open(r'D:\python_workspace\my_geetest_crack\ast_js\gct\gct.raw5.js') as f:
    #     gct_js = f.read()
    #     print(get_w2_dy_kv(gct_js))

    # gct test
    # ff1 = r'function RFEK(t){var nMl=AFfNy.EJX()[0][8];for(;nMl!==AFfNy.EJX()[2][6];){switch(nMl){case AFfNy.EJX()[6][8]:var e=5381;var n=t[Dyqd(82)];var r=0;nMl=AFfNy.EJX()[0][7];break;case AFfNy.EJX()[6][7]:while(n--){e=(e<<5)+e+t[Dyqd(94)](r++);}e&=~(1<<31);return e;break;}}}'
    # ff2 = r'function SFjo(t){var oZW=AFfNy.EJX()[0][8];for(;oZW!==AFfNy.EJX()[4][7];){switch(oZW){case AFfNy.EJX()[4][8]:if(t[Dyqd(68)]&&t[Dyqd(69)]){t[e]=RFEK(SFjo[EEc_(58)]()+RFEK(RFEK[Dyqd(58)]()))+Dyqd(40);}function Oo(){var peb=AFfNy.EJX()[6][8];for(;peb!==AFfNy.EJX()[4][7];){switch(peb){case AFfNy.EJX()[6][8]:this[Dyqd(68)]=t[Dyqd(68)];this[EEc_(69)]=t[Dyqd(69)];peb=AFfNy.EJX()[4][7];break;}}}Oo[EEc_(56)]=new TnzE();function TnzE(){var qsg=AFfNy.EJX()[2][8];for(;qsg!==AFfNy.EJX()[4][8];){switch(qsg){}}}TnzE[EEc_(56)][Dyqd(65)]={"\u006e":Hi_U,"\u0073":FnfH,"\u0065":li,"\u0065\u0073":MPUm,"\u0065\u006e":IXwV,"\u0077":KnvZ,"\u0077\u006e":LKya,"\u0077\u0073":Jddh,"\u0066":QZlh};return new Oo();break;}}}'
    # res = my_gct_js.call('FkFz', ff1)
    # res2 = my_gct_js.call('FkFz', ff2 + str(res))
    # res3 = my_gct_js.call('cal_gct_value', 'gdmb', ff1, ff2)
    # print(res)
    # print(res2)
    # print(res3)

    # get.php[1] w
    # gt = '3a99b6b7637b498ac1f7c02bafa7e9bc'
    # challenge = '5f699958e71effa0175d21f910674de5'
    # s = 'a74e0265d79f830b'
    # get_w1 = get_full_page_w1(gt, challenge, s)
    # print(get_w1)

    # ajax.php[1] w
    # challenge = '452231a723a28a2e05c5161b47ee3381'
    # s = 'a4f8268cb17dfc07'
    # get_data = {
    #     "status": "success",
    #     "data": {
    #         "logo": False,
    #         "feedback": "",
    #         "c": [12, 58, 98, 36, 43, 95, 62, 15, 12],
    #         "s": "4d522832",
    #         "theme": "wind",
    #         "i18n_labels": {
    #             "read_reversed": False,
    #             "error_title": "\u7f51\u7edc\u8d85\u65f6",
    #             "loading_content": "\u667a\u80fd\u9a8c\u8bc1\u68c0\u6d4b\u4e2d",
    #             "copyright": "\u7531\u6781\u9a8c\u63d0\u4f9b\u6280\u672f\u652f\u6301",
    #             "refresh_page": "\u9875\u9762\u51fa\u73b0\u9519\u8bef\u5566\uff01\u8981\u7ee7\u7eed\u64cd\u4f5c\uff0c\u8bf7\u5237\u65b0\u6b64\u9875\u9762",
    #             "ready": "\u70b9\u51fb\u6309\u94ae\u8fdb\u884c\u9a8c\u8bc1",
    #             "goto_confirm": "\u524d\u5f80",
    #             "error_content": "\u8bf7\u70b9\u51fb\u6b64\u5904\u91cd\u8bd5",
    #             "error": "\u7f51\u7edc\u4e0d\u7ed9\u529b",
    #             "goto_homepage": "\u662f\u5426\u524d\u5f80\u9a8c\u8bc1\u670d\u52a1Geetest\u5b98\u7f51",
    #             "next": "\u6b63\u5728\u52a0\u8f7d\u9a8c\u8bc1",
    #             "success_title": "\u901a\u8fc7\u9a8c\u8bc1",
    #             "success": "\u9a8c\u8bc1\u6210\u529f",
    #             "reset": "\u8bf7\u70b9\u51fb\u91cd\u8bd5",
    #             "fullpage": "\u667a\u80fd\u68c0\u6d4b\u4e2d",
    #             "goto_cancel": "\u53d6\u6d88",
    #             "next_ready": "\u8bf7\u5b8c\u6210\u9a8c\u8bc1"
    #         },
    #         "theme_version": "1.5.8",
    #         "static_servers": ["static.geetest.com", "dn-staticdown.qbox.me"],
    #         "api_server": "api.geetest.com"
    #     }
    # }
    # ajax_w1 = get_full_page_w2(gt, challenge, s, get_data)
    # print(ajax_w1)

    # ajax.php[2] w
    # challenge = '7e64a0f738a084cabaa33263faf5ad79gz'
    # s = '6df103a2c207dda1'
    # track = [[-44, -37, 0], [0, 0, 0], [0, 0, 35], [2, 0, 118], [4, 0, 127], [8, 0, 134], [12, 0, 145], [17, 0, 150], [20, 0, 158], [25, 0, 166], [32, 1, 174], [36, 1, 183], [41, 2, 191], [44, 2, 198], [48, 3, 206], [55, 4, 214], [59, 5, 222], [64, 6, 230], [69, 6, 244], [76, 7, 247], [81, 8, 256], [114, 12, 313], [118, 13, 331], [120, 15, 334], [122, 15, 342], [123, 15, 350], [124, 15, 358], [126, 16, 462], [127, 16, 486], [128, 16, 495], [129, 16, 502], [131, 16, 511], [133, 17, 518], [135, 17, 528], [137, 17, 534], [138, 17, 542], [140, 17, 550], [142, 17, 558], [144, 17, 566], [147, 17, 574], [148, 19, 582], [150, 19, 590], [152, 20, 598], [154, 20, 622], [153, 20, 1158], [152, 20, 1182], [151, 20, 1207], [150, 20, 1294], [149, 20, 1342], [148, 20, 1646], [147, 20, 1678], [145, 20, 1934], [145, 19, 2111], [145, 19, 2407]]
    # offset = track[-1][0]
    # cc = [12, 58, 98, 36, 43, 95, 62, 15, 12]
    # ss = '2a725a36'
    # ajax_w2 = get_slide_w(gt, challenge, s, track, cc, ss)
    # print(ajax_w2)
